// Copyright 2021 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tree

import (
	"go/constant"
	"strings"
)

//the AST for literals like string,numeric,bool and etc.
type Constant interface {
	Expr
}

//the AST for the constant numeric value.
type NumVal struct {
	Constant
	Value constant.Value

	// negative is the sign label
	negative bool

	// origString is the "original" string literals that should remain sign-less.
	origString string

	//converted result
	resInt   int64
	resFloat float64
}

func (node *NumVal) Format(ctx *FmtCtx) {
	if node.origString != "" {
		ctx.WriteString(node.origString)
		return
	}
	switch node.Value.Kind() {
	case constant.Bool:
		ctx.WriteString(strings.ToLower(node.Value.String()))
	case constant.Unknown:
		ctx.WriteString("null")
	}
}

func (n *NumVal) String() string {
	return n.origString
}

func (n *NumVal) Negative() bool {
	return n.negative
}

func NewNumVal(value constant.Value, origString string, negative bool) *NumVal {
	return &NumVal{
		Value:      value,
		origString: origString,
		negative:   negative,
	}
}

func NewNumValWithResInt(value constant.Value, origString string, negative bool, resInt int64) *NumVal {
	return &NumVal{
		Value:      value,
		origString: origString,
		negative:   negative,
		resInt:     resInt,
	}
}

func NewNumValWithResFoalt(value constant.Value, origString string, negative bool, resFloat float64) *NumVal {
	return &NumVal{
		Value:      value,
		origString: origString,
		negative:   negative,
		resFloat:   resFloat,
	}
}

// StrVal represents a constant string value.
type StrVal struct {
	Constant
	str string
}

func (node *StrVal) Format(ctx *FmtCtx) {
	ctx.WriteString(node.str)
}

func NewStrVal(s string) *StrVal {
	return &StrVal{str: s}
}
